package org.upo.eps.it.phama.dao;

import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.upo.eps.it.phama.bean.DetallePedCli;
import org.upo.eps.it.phama.bean.PedidoCliente;
import org.upo.eps.it.phama.util.HibernateUtil;

/**
 *
 * @author grupo 4
 */
public class PedidoClienteDAO {

    /**
     * Devuelve el objeto de la clase PedidoCliente que corresponda con el id
     * aportado como parámetro. Si no se encontrara, se obtiene nulo.
     *
     * @param idPedido Integer con el número de pedido que se quiere obtener
     * @return
     */
    public static PedidoCliente getById(Integer idPedido) {
        PedidoCliente resultado;

        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        resultado = (PedidoCliente) session.get(PedidoCliente.class, idPedido);
        session.close();

        return resultado;
    }

    /**
     * Efectúa la búsqueda de todos los pedidos de clientes cuyos atributos
     * coincidan con todos los parámetros recibidos. La búsqueda se realiza
     * concatenando todos los parámetros de forma que cuantos más se aporten,
     * más restrictivo será el resultado.
     *
     * @param idCliente Integer con el id del cliente al que pertenece el pedido
     * buscado.
     * @param id Integer con el id del pedido buscado.
     * @param fecha String representando la fecha del pedido buscado.
     * @return Lista de objetos de la clase PedidoCliente.
     */
    public static List<PedidoCliente> search(int idCliente, int id, String fecha) {
        List<PedidoCliente> resultado;
        /*
         * Se redefinen los parámetros de búsqueda de manera que puedan incluirse en 
         * la misma aquellos registros cuyos parámetros no se hayan aportado.
         */
        String c = idCliente == 0 ? "%" : String.valueOf(idCliente);
        String i = id == 0 ? "%" : String.valueOf(id);
        String f = fecha.isEmpty() ? "%" : fecha;

        /*
         * Se obtiene una sesión, se define la cadena de búsqueda a base de concatenaciones
         * and y comparadores like y finalmente se ejecuta la consulta.
         */
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        String sql = String.format("from PedidoCliente where id like '%s' and cliente like '%s' and fecha like '%s'", i, c, f);
        Query qry = session.createQuery(sql);
        resultado = (List<PedidoCliente>) qry.list();
        session.close();

        return resultado;
    }

    /**
     * Se obtiene una lista de todos los registros hijos (detalle)
     * correspondientes al pedido cuyo id se recibe como parámetro.
     *
     * @param idPedido Integer con el id correspondiente al pedido cuyo detalle
     * se quiere obtener.
     * @return Lista de objetos de la clase DetallePedCli.
     */
    public static List<DetallePedCli> searchDetalle(int idPedido) {
        List<DetallePedCli> resultado;
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        String sql = String.format("from DetallePedCli where id.idPedidoCli = %d", idPedido);
        Query qry = session.createQuery(sql);
        resultado = (List<DetallePedCli>) qry.list();
        session.close();

        return resultado;
    }

    /**
     * Se hace persistente el objeto de la clase PedidoCliente recibido como
     * parámetro.
     *
     * @param pedido Objeto de la clase PedidoCliente que se quiere persistir.
     */
    public static void save(PedidoCliente pedido) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        try {
            /* Primero se persiste el objeto pedido, lo que permite obtener un número
             * de identificador. Éste se usará a continuación para completar la clave
             * primaria de los objetos detalle, que igualmente se van persistiendo.
             */
            session.saveOrUpdate(pedido);
            for (DetallePedCli detalle : pedido.getMisDetallesPedCli()) {
                detalle.getId().setIdPedidoCli(pedido.getIdPedidoCli());
                session.saveOrUpdate(detalle);
            }

            // Finalmente, se asegura toda la transaccion o se revierte si algo fallara.
            session.getTransaction().commit();
        } catch (HibernateException ex) {
            session.getTransaction().rollback();
            throw ex;
        }
    }

    /**
     * Se persisten los cambios efectuados en el objeto recibido como parámetro.
     *
     * @param pedido Objeto de la clase PedidoCliente cuyos cambios se quieren
     * guardar.
     */
    public static void update(PedidoCliente pedido) {
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        /* Primero se recorre toda la lista de detalles del pedido, cuya clave primaria
         * se completa con el id del propio pedido, que ya existe, al tiempo que se 
         * persiste.
         */
        try {
            for (DetallePedCli detalle : pedido.getMisDetallesPedCli()) {
                detalle.getId().setIdPedidoCli(pedido.getIdPedidoCli());
                session.saveOrUpdate(detalle);
            }
            /* Posteriormente, el objeto pedido se une con aquél de la base de datos cuya
             * clave primera sea igua a la de éste. Es la manera de persistir un objeto
             * que ha sido creado directamente en memoria, es decir, que no es el resultado
             * de una consulta previa a la base de datos.
             */
            session.merge(pedido);
            session.flush();
            session.getTransaction().commit();
        } catch (HibernateException ex) {
            session.getTransaction().rollback();
            throw ex;
        }
    }

    /**
     * Elimina de la base de datos el objeto de la clase PedidoCliente cuyo id
     * corresponde con el parámetro recibido.
     *
     * @param id Integer representando el identificador del pedido de cliente
     * que se quiere eliminar.
     * @throws HibernateException
     */
    public static void delete(int idPedido) throws HibernateException {
        PedidoCliente pedido;
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        try {
            pedido = (PedidoCliente) session.get(PedidoCliente.class, idPedido);
            // Antes de eliminar el pedido es necesario quitar cualquier referencia al mismo en todas sus colecciones hijas.
            pedido.getEstado().getMisPedidosCliente().remove(pedido);
            pedido.getCliente().getMisPedidosCliente().remove(pedido);
            session.delete(pedido);
            session.getTransaction().commit();
        } catch (HibernateException ex) {
            session.getTransaction().rollback();
            throw ex;
        }
    }

    public static int getNextIdDetalle(Integer idPedido) {
        Object result;
        Session session = HibernateUtil.getSessionFactory().getCurrentSession();
        session.beginTransaction();
        String sql = String.format("select max(id.idDetalle) from DetallePedCli where id.idPedidoCli = %d", idPedido);
        Query qry = session.createQuery(sql);
        result = qry.uniqueResult();
        session.close();

        return result==null?0:(int)result;
    }
}
